// Copyright 2007-2010 Comdiv (F. Sadykov) - http://code.google.com/u/fagim.sadykov/
// Supported by Media Technology LTD 
//  
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//  
//      http://www.apache.org/licenses/LICENSE-2.0
//  
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// 
// MODIFICATIONS HAVE BEEN MADE TO THIS FILE
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;

namespace Comdiv.Extensions{
    ///<summary>
    ///</summary>
    /// 
    [DebuggerStepThrough]
    public static class DictionaryExtensions{

        


        public static T get<K, T>(this IDictionary<K, T> dict, K key){
            return get<K, T>(dict, key, default(T),false);
        }

        public static T get<K, T>(this IDictionary<K, T> dict, K key, T def){
            return get<K, T>(dict, key, def, true);
        }

        public static T get<T>(this IDictionary<string,object> dict,string key,T def){
            return get<T>(dict, key, def, true);
        }

        public static T get<T>(this IDictionary<string,object> dict,string key,T def, bool init)
        {
            return (T) get<T>((IDictionary)dict, key, def,init);
        }


        

        

        public static T get<K, T>(this IDictionary<K, T> dict, K key, T def, bool init)
        {
            //HACK: all descendants of generic Dictionary are IDictionary too
            return get((IDictionary)dict, key, () => def, init);
        }


        public static T get<K, T>(this IDictionary<K, T> dict, K key, Func<T> def)
        {
            return get(dict, key, def, true);
        }

        public static T get<K,T>(this IDictionary<K,T> dict, K key, Func<T> def, bool init)
        {
            def = def ?? (()=>default(T));
            //HACK: all descendants of generic Dictionary are IDictionary too
            return (T) get((IDictionary)dict, key, () => (object)def(), init);
        }


        public static R get<R>(this IDictionary<string,object> dict, string key)
        {
            return get<R>((IDictionary)dict, key, default(R),false);
        }
       
        public static R get<R>(this IDictionary dict, object key, object def)
        {
            return get<R>(dict, key, def, true);
        }

        public static R get<R>(this IDictionary dict, object key, object def, bool init)
        {
            //HACK: all descendants of generic Dictionary are IDictionary too
            return get<R>(dict, key, () =>(R) def, init);
        }


       

        public static R get<R>(this IDictionary dict, object key, Func<R> def, bool init)
        {
            //HACK: all descendants of generic Dictionary are IDictionary too
            return get(dict, key, () =>(object) def(), init).to<R>();


        }

       
        

        

        public static R get<R,K>(this IDictionary<K,object> dict, K key, Func<R> def)
        {
            return get<R,K>(dict, key, def, true);
        }

        public static R get<R,K>(this IDictionary<K,object> dict, K key, Func<R> def, bool init)
        {
            def = def ?? (()=>default(R));
            //HACK: all descendants of generic Dictionary are IDictionary too
            return get((IDictionary)dict, key,()=>(object) def(), init).to<R>();
        }




        public static object get(this IDictionary dict, object key, Func<object> def, bool init){
            if(null==dict||null==key) return def();
            if (dict.Contains(key)) return dict[key];
            
            var res = def();
            if (init && null!=res) dict[key] = res;
            return res;
        }

        
    }
}